home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 21 / Cream of the Crop 21 (Terry Blount) (October 1996).iso / program / oxcc1434.zip / SRC / CFLS.C < prev    next >
C/C++ Source or Header  |  1995-10-20  |  74KB  |  2,977 lines

  1. /* `dir', `vdir' and `ls' directory listing programs for GNU.
  2.    Copyright (C) 1985, 1988, 1989, 1990 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 1, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /* If the macro MULTI_COL is defined,
  19.    the multi-column format is the default regardless
  20.    of the type of output device.
  21.    This is for the `dir' program.
  22.  
  23.    If the macro LONG_FORMAT is defined,
  24.    the long format is the default regardless of the
  25.    type of output device.
  26.    This is for the `vdir' program.
  27.  
  28.    If neither is defined,
  29.    the output format depends on whether the output
  30.    device is a terminal.
  31.    This is for the `ls' program. */
  32.  
  33. /* Written by Richard Stallman and David MacKenzie. */
  34. /* Modified for PCDOS and 32 Char filenames by Norman D. Culver */
  35. /* Additonal mods for cff */
  36.  
  37. #include "cfls.h"
  38.  
  39.  
  40. /* Return an int indicating the result of comparing two longs. */
  41. #ifdef INT_16_BITS
  42. #define longdiff(a, b) ((a) < (b) ? -1 : (a) > (b) ? 1 : 0)
  43. #else
  44. #define longdiff(a, b) ((a) - (b))
  45. #endif
  46.  
  47. int glob_match ();
  48.  
  49. char *copystring ();
  50. char *getgroup ();
  51. char *getuser ();
  52. char *make_link_path ();
  53. char *xmalloc ();
  54. char *xrealloc ();
  55. int argmatch ();
  56. int compare_atime ();
  57. int rev_cmp_atime ();
  58. int compare_ctime ();
  59. int rev_cmp_ctime ();
  60. int compare_mtime ();
  61. int rev_cmp_mtime ();
  62. int compare_size ();
  63. int rev_cmp_size ();
  64. int compare_name ();
  65. int rev_cmp_name ();
  66. int compare_extension ();
  67. int rev_cmp_extension ();
  68. int decode_switches ();
  69. int file_interesting ();
  70. long gobble_file ();
  71. int is_not_dot_or_dotdot ();
  72. int length_of_file_name_and_frills ();
  73. void add_ignore_pattern ();
  74. void add_list_pattern ();
  75. void attach ();
  76. void clear_files ();
  77. void error ();
  78. void extract_dirs_from_files ();
  79. void get_link_name ();
  80. void indent ();
  81. void invalid_arg ();
  82. void print_current_files ();
  83. void print_dir ();
  84. void print_file_name_and_frills ();
  85. void print_horizontal ();
  86. void print_long_format ();
  87. void print_many_per_line ();
  88. void print_name_with_quoting ();
  89. void print_type_indicator ();
  90. void print_with_commas ();
  91. void queue_directory ();
  92. void sort_files ();
  93. void usage ();
  94.  
  95. enum filetype
  96. {
  97.   symbolic_link,
  98.   directory,
  99.   arg_directory,    /* Directory given as command line arg. */
  100.   normal      /* All others. */
  101. };
  102. typedef struct _lstat {
  103.     unsigned long st_mode;
  104.     unsigned long st_atime;
  105.     unsigned long st_mtime;
  106.     unsigned long st_ctime;
  107.     unsigned long st_ino;
  108.     unsigned long st_size;
  109.     unsigned long st_alloc;
  110. } LSTAT;
  111.  
  112. struct file
  113. {
  114.   /* The file name. */
  115.   char *name;
  116.   int namlen;
  117.   LSTAT stats;
  118.   char *linkname;
  119.   unsigned long linkmode;
  120.   enum filetype filetype;
  121. };
  122.  
  123. /* The table of files in the current directory:
  124.  
  125.    `files' points to a vector of `struct file', one per file.
  126.    `nfiles' is the number of elements space has been allocated for.
  127.    `files_index' is the number actually in use.  */
  128.  
  129. /* Address of block containing the files that are described.  */
  130.  
  131. struct file *files;
  132.  
  133. /* Length of block that `files' points to, measured in files.  */
  134.  
  135. int nfiles;
  136.  
  137. /* Index of first unused in `files'.  */
  138.  
  139. int files_index;
  140.  
  141. /* Record of one pending directory waiting to be listed.  */
  142.  
  143. struct pending
  144. {
  145.   char *name;
  146.   /* If the directory is actually the file pointed to by a symbolic link we
  147.      were told to list, `realname' will contain the name of the symbolic
  148.      link, otherwise zero. */
  149.   char *realname;
  150.   struct ignore_pattern *list_patterns;
  151.   struct pending *next;
  152. };
  153.  
  154. struct pending *pending_dirs;
  155.  
  156. /* Current time (seconds since 1970).  When we are printing a file's time,
  157.    include the year if it is more than 6 months before this time.  */
  158.  
  159. long current_time;
  160.  
  161. /* The number of digits to use for block sizes.
  162.    4, or more if needed for bigger numbers.  */
  163.  
  164. int block_size_size;
  165.  
  166. /* The name the program was run with, stripped of any leading path. */
  167. char *program_name;
  168.  
  169. /* Option flags */
  170.  
  171. /* long_format for lots of info, one per line.
  172.    one_per_line for just names, one per line.
  173.    many_per_line for just names, many per line, sorted vertically.
  174.    horizontal for just names, many per line, sorted horizontally.
  175.    with_commas for just names, many per line, separated by commas.
  176.  
  177.    -l, -1, -C, -x and -m control this parameter.  */
  178.  
  179. enum format
  180. {
  181.   long_format,      /* -l */
  182.   one_per_line,     /* -1 */
  183.   many_per_line,    /* -C */
  184.   horizontal,     /* -x */
  185.   with_commas     /* -m */
  186. };
  187.  
  188. enum format format;
  189.  
  190. /* Type of time to print or sort by.  Controlled by -c and -u.  */
  191.  
  192. enum time_type
  193. {
  194.   time_mtime,     /* default */
  195.   time_ctime,     /* -c */
  196.   time_atime      /* -u */
  197. };
  198.  
  199. enum time_type time_type;
  200.  
  201. /* The file characteristic to sort by.  Controlled by -t, -S, -U, -X. */
  202.  
  203. enum sort_type
  204. {
  205.   sort_none,      /* -U */
  206.   sort_name,      /* default */
  207.   sort_extension,   /* -X */
  208.   sort_time,      /* -t */
  209.   sort_size     /* -S */
  210. };
  211.  
  212. enum sort_type sort_type;
  213.  
  214. /* Direction of sort.
  215.    0 means highest first if numeric,
  216.    lowest first if alphabetic;
  217.    these are the defaults.
  218.    1 means the opposite order in each case.  -r  */
  219.  
  220. int sort_reverse;
  221.  
  222. /* Nonzero means print the user and group id's as numbers rather
  223.    than as names.  -n  */
  224.  
  225. int numeric_users;
  226.  
  227. /* Nonzero means mention the size in 512 byte blocks of each file.  -s  */
  228.  
  229. int print_block_size;
  230.  
  231. /* Nonzero means show file sizes in kilobytes instead of blocks
  232.    (the size of which is system-dependant).  -k */
  233.  
  234. int kilobyte_blocks;
  235.  
  236. /* none means don't mention the type of files.
  237.    all means mention the types of all files.
  238.    not_programs means do so except for executables.
  239.  
  240.    Controlled by -F and -p.  */
  241.  
  242. enum indicator_style
  243. {
  244.   none,       /* default */
  245.   all,        /* -F */
  246.   not_programs      /* -p */
  247. };
  248.  
  249. enum indicator_style indicator_style;
  250.  
  251. /* Nonzero means mention the inode number of each file.  -i  */
  252.  
  253. int print_inode;
  254.  
  255. /* Nonzero means when a symbolic link is found, display info on
  256.    the file linked to.  -L  */
  257.  
  258. int trace_links;
  259.  
  260. /* Nonzero means when a directory is found, display info on its
  261.    contents.  -R  */
  262.  
  263. int trace_dirs;
  264.  
  265. /* Nonzero means when an argument is a directory name, display info
  266.    on it itself.  -d  */
  267.  
  268. int immediate_dirs;
  269.  
  270. /* Nonzero means don't omit files whose names start with `.'.  -A */
  271.  
  272. int all_files;
  273.  
  274. /* Nonzero means don't omit files `.' and `..'
  275.    This flag implies `all_files'.  -a  */
  276.  
  277. int really_all_files;
  278.  
  279. /* A linked list of shell-style globbing patterns.  If a non-argument
  280.    file name matches any of these patterns, it is omitted, or listed.
  281.    List_patterns only occur if the shell fails to glob a pattern on
  282.    the command line, PCDOS is a good example. Ignore_patterns are
  283.    controlled by -I.  Multiple -I options accumulate.
  284.    The -B option adds `*~' and `.*~' to this list.  */
  285.  
  286. struct ignore_pattern
  287. {
  288.   char *pattern;
  289.   struct ignore_pattern *next;
  290. };
  291.  
  292. struct ignore_pattern *ignore_patterns;
  293.  
  294. /* Nonzero means quote nongraphic chars in file names.  -b  */
  295.  
  296. int quote_funny_chars;
  297.  
  298. /* Nonzero means output nongraphic chars in file names as `?'.  -q  */
  299.  
  300. int qmark_funny_chars;
  301.  
  302. /* Nonzero means output each file name using C syntax for a string.
  303.    Always accompanied by `quote_funny_chars'.
  304.    This mode, together with -x or -C or -m,
  305.    and without such frills as -F or -s,
  306.    is guaranteed to make it possible for a program receiving
  307.    the output to tell exactly what file names are present.  -Q  */
  308.  
  309. int quote_as_string;
  310.  
  311. /* The number of chars per hardware tab stop.  -T */
  312. int tabsize;
  313.  
  314. /* Nonzero means we are listing the working directory because no
  315.    non-option arguments were given. */
  316.  
  317. int dir_defaulted;
  318.  
  319. /* Nonzero means print each directory name before listing it. */
  320.  
  321. int print_dir_name;
  322.  
  323. /* The line length to use for breaking lines in many-per-line format.
  324.    Can be set with -w.  */
  325.  
  326. int line_length;
  327.  
  328. /* If nonzero, the file listing format requires that stat be called on
  329.    each file. */
  330.  
  331. int format_needs_stat;
  332.  
  333. struct option long_options[] =
  334. {
  335.   {"all", 0, NULL, 'a'},
  336.   {"escape", 0, NULL, 'b'},
  337.   {"directory", 0, NULL, 'd'},
  338.   {"inode", 0, NULL, 'i'},
  339.   {"kilobytes", 0, NULL, 'k'},
  340.   {"numeric-uid-gid", 0, NULL, 'n'},
  341.   {"hide-control-chars", 0, NULL, 'q'},
  342.   {"reverse", 0, NULL, 'r'},
  343.   {"size", 0, NULL, 's'},
  344.   {"width", 1, NULL, 'w'},
  345.   {"almost-all", 0, NULL, 'A'},
  346.   {"ignore-backups", 0, NULL, 'B'},
  347.   {"classify", 0, NULL, 'F'},
  348.   {"file-type", 0, NULL, 'F'},
  349.   {"ignore", 1, NULL, 'I'},
  350.   {"dereference", 0, NULL, 'L'},
  351.   {"literal", 0, NULL, 'N'},
  352.   {"quote-name", 0, NULL, 'Q'},
  353.   {"recursive", 0, NULL, 'R'},
  354.   {"format", 1, NULL, 12},
  355.   {"sort", 1, NULL, 10},
  356.   {"tabsize", 1, NULL, 'T'},
  357.   {"time", 1, NULL, 11},
  358.   {NULL, 0, NULL, 0}
  359. };
  360.  
  361. char *format_args[] =
  362. {
  363.   "verbose", "long", "commas", "horizontal", "across",
  364.   "vertical", "single-column", NULL
  365. };
  366.  
  367. enum format formats[] =
  368. {
  369.   long_format, long_format, with_commas, horizontal, horizontal,
  370.   many_per_line, one_per_line
  371. };
  372.  
  373. char *sort_args[] =
  374. {
  375.   "none", "time", "size", "extension", 0
  376. };
  377.  
  378. enum sort_type sort_types[] =
  379. {
  380.   sort_none, sort_time, sort_size, sort_extension
  381. };
  382.  
  383. char *time_args[] =
  384. {
  385.   "atime", "access", "use", "ctime", "status", 0
  386. };
  387.  
  388. enum time_type time_types[] =
  389. {
  390.   time_atime, time_atime, time_atime, time_ctime, time_ctime
  391. };
  392. static int
  393. is_printable(const char *cp, int len)
  394. {
  395. register int i;
  396.     for(i = 0; i < len; ++i) {
  397.         if(!isgraph(cp[i])) {
  398.             if(cp[i] == '\0')
  399.                 break;
  400.             return 0;
  401.         }
  402.     }
  403.     return (i > 0) ? 1 : 0;
  404. }
  405. /* Set all the option flags according to the switches specified.
  406.    Return the index of the first non-option argument.  */
  407.  
  408. int
  409. decode_switches (argc, argv)
  410. int argc;
  411. char **argv;
  412.  
  413. {
  414.   register char *p;
  415.   int c;
  416.   int longind;
  417.  
  418.   qmark_funny_chars = 0;
  419.   quote_funny_chars = 0;
  420.  
  421.   /* initialize all switches to default settings */
  422.  
  423. #ifdef MULTI_COL
  424. #define PROGNAME "dir"
  425.   /* This is for the `dir' program.  */
  426.   format = many_per_line;
  427.   quote_funny_chars = 1;
  428. #else
  429. #ifdef LONG_FORMAT
  430. #define PROGNAME "vdir"
  431.   /* This is for the `vdir' program.  */
  432.   format = long_format;
  433.   quote_funny_chars = 1;
  434. #else
  435. #define PROGNAME "cfls"
  436.   /* This is for the `ls' program.  */
  437.   if (isatty (1))
  438.   {
  439.     format = many_per_line;
  440.     qmark_funny_chars = 1;
  441.   }
  442.   else
  443.   {
  444.     format = one_per_line;
  445.     qmark_funny_chars = 0;
  446.   }
  447. #endif
  448. #endif
  449.  
  450.   time_type = time_mtime;
  451.   sort_type = sort_name;
  452.   sort_reverse = 0;
  453.   numeric_users = 0;
  454.   print_block_size = 0;
  455.   kilobyte_blocks = 0;
  456.   indicator_style = none;
  457.   print_inode = 0;
  458.   trace_links = 0;
  459.   trace_dirs = 0;
  460.   immediate_dirs = 0;
  461.   all_files = 0;
  462.   really_all_files = 0;
  463.   ignore_patterns = 0;
  464.   quote_as_string = 0;
  465.  
  466.   p = getenv ("COLUMNS");
  467.   line_length = p ? atoi (p) : 80;
  468.  
  469. #ifdef TIOCGWINSZ
  470.   {
  471.     struct winsize ws;
  472.  
  473.     if (ioctl (1, TIOCGWINSZ, &ws) != -1 && ws.ws_col != 0)
  474.       line_length = ws.ws_col;
  475.   }
  476. #endif
  477.  
  478.   p = getenv ("TABSIZE");
  479.   tabsize = p ? atoi (p) : 8;
  480.  
  481.   while ((c = getopt_long (argc, argv, "abcdgiklmnpqrstuw:xABCFI:LNQRST:UX1",
  482.          long_options, &longind)) != EOF)
  483.   {
  484.     switch (c)
  485.     {
  486.       case 'a':
  487.         all_files = 1;
  488.         really_all_files = 1;
  489.         break;
  490.  
  491.       case 'b':
  492.         quote_funny_chars = 1;
  493.         qmark_funny_chars = 0;
  494.         break;
  495.  
  496.       case 'c':
  497.         time_type = time_ctime;
  498.         break;
  499.  
  500.       case 'd':
  501.         immediate_dirs = 1;
  502.         break;
  503.  
  504.       case 'g':
  505.     /* No effect.  For BSD compatibility. */
  506.         break;
  507.  
  508.       case 'i':
  509.         print_inode = 1;
  510.         break;
  511.  
  512.       case 'k':
  513.         kilobyte_blocks = 1;
  514.         break;
  515.  
  516.       case 'l':
  517.         format = long_format;
  518.         break;
  519.  
  520.       case 'm':
  521.         format = with_commas;
  522.         break;
  523.  
  524.       case 'n':
  525.         numeric_users = 1;
  526.         break;
  527.  
  528.       case 'p':
  529.         indicator_style = not_programs;
  530.         break;
  531.  
  532.       case 'q':
  533.         qmark_funny_chars = 1;
  534.         quote_funny_chars = 0;
  535.         break;
  536.  
  537.       case 'r':
  538.         sort_reverse = 1;
  539.         break;
  540.  
  541.       case 's':
  542.         print_block_size = 1;
  543.         break;
  544.  
  545.       case 't':
  546.         sort_type = sort_time;
  547.         break;
  548.  
  549.       case 'u':
  550.         time_type = time_atime;
  551.         break;
  552.  
  553.       case 'w':
  554.         line_length = atoi (optarg);
  555.         if (line_length < 1)
  556.           error (1, 0, "invalid line width: %s", optarg);
  557.         break;
  558.  
  559.       case 'x':
  560.         format = horizontal;
  561.         break;
  562.  
  563.       case 'A':
  564.         all_files = 1;
  565.         break;
  566.  
  567.       case 'B':
  568.         add_ignore_pattern ("*~");
  569.         add_ignore_pattern (".*~");
  570.         break;
  571.  
  572.       case 'C':
  573.         format = many_per_line;
  574.         break;
  575.  
  576.       case 'F':
  577.         indicator_style = all;
  578.         break;
  579.  
  580.       case 'I':
  581.         add_ignore_pattern (optarg);
  582.         break;
  583.  
  584.       case 'L':
  585.         trace_links = 1;
  586.         break;
  587.  
  588.       case 'N':
  589.         quote_funny_chars = 0;
  590.         qmark_funny_chars = 0;
  591.         break;
  592.  
  593.       case 'Q':
  594.         quote_as_string = 1;
  595.         quote_funny_chars = 1;
  596.         qmark_funny_chars = 0;
  597.         break;
  598.  
  599.       case 'R':
  600.         trace_dirs = 1;
  601.         break;
  602.  
  603.       case 'S':
  604.         sort_type = sort_size;
  605.         break;
  606.  
  607.       case 'T':
  608.         tabsize = atoi (optarg);
  609.         if (tabsize < 1)
  610.           error (1, 0, "invalid tab size: %s", optarg);
  611.         break;
  612.  
  613.       case 'U':
  614.         sort_type = sort_none;
  615.         break;
  616.  
  617.       case 'X':
  618.         sort_type = sort_extension;
  619.         break;
  620.  
  621.       case '1':
  622.         format = one_per_line;
  623.         break;
  624.  
  625.       case 10:    /* +sort */
  626.         longind = argmatch (optarg, sort_args);
  627.         if (longind < 0)
  628.         {
  629.           invalid_arg ("sort type", optarg, longind);
  630.           usage ();
  631.         }
  632.         sort_type = sort_types[longind];
  633.         break;
  634.  
  635.       case 11:    /* +time */
  636.         longind = argmatch (optarg, time_args);
  637.         if (longind < 0)
  638.         {
  639.           invalid_arg ("time type", optarg, longind);
  640.           usage ();
  641.         }
  642.         time_type = time_types[longind];
  643.         break;
  644.  
  645.       case 12:    /* +format */
  646.         longind = argmatch (optarg, format_args);
  647.         if (longind < 0)
  648.         {
  649.           invalid_arg ("format type", optarg, longind);
  650.           usage ();
  651.         }
  652.         format = formats[longind];
  653.         break;
  654.  
  655.       default:
  656.         usage ();
  657.     }
  658.   }
  659.  
  660.   return optind;
  661. }
  662.  
  663. /* Request that the directory named `name' have its contents listed later.
  664.    If `realname' is nonzero, it will be used instead of `name' when the
  665.    directory name is printed.  This allows symbolic links to directories
  666.    to be treated as regular directories but still be listed under their
  667.    real names. */
  668.  
  669. void
  670. queue_directory (name, realname, thispend)
  671.      char *name;
  672. char *realname;
  673. struct pending *thispend;
  674.  
  675. {
  676.   struct pending *new;
  677.  
  678.   new = (struct pending *) xmalloc (sizeof (struct pending));
  679.   new->next = pending_dirs;
  680.   pending_dirs = new;
  681.   new->name = copystring (name);
  682.   if (realname)
  683.     new->realname = copystring (realname);
  684.   else
  685.     new->realname = NULL;
  686.   if(thispend)
  687.     new->list_patterns = thispend->list_patterns;
  688.   else
  689.     new->list_patterns = NULL;
  690. }
  691.  
  692. /* Read directory `name', and list the files in it.
  693.    If `realname' is nonzero, print its name instead of `name';
  694.    this is used for symbolic links to directories. */
  695.  
  696. void
  697. print_dir (thispend)
  698.   struct pending *thispend;
  699.  
  700. {
  701.   register void *reading;
  702.   CFDIRENT *next;
  703.   register long total_blocks = 0;
  704.   char *name;
  705.   char *realname;
  706.  
  707.   errno = 0;
  708.   name = thispend->name;
  709.   realname = thispend->realname;
  710.  
  711.   reading = opendir (name);
  712.   if (!reading)
  713.   {
  714. #ifdef PCDOS
  715.     errno = 2;/* it seems to have a small vocabulary, so ENOENT */
  716. #endif
  717.     error (0, errno, "%s", name);
  718.     return;
  719.   }
  720.   /* Read the directory entries, and insert the subfiles into the `files'
  721.      table.  */
  722.   clear_files ();
  723.  
  724.   while (next = (void*)readdir (reading))
  725.   {
  726.     if (file_interesting (next, thispend))
  727.       total_blocks += gobble_file (next->d_name, 0, name, next);
  728.   }
  729.   closedir (reading);
  730.  
  731.   /* Sort the directory contents.  */
  732.   sort_files ();
  733.  
  734.   /* If any member files are subdirectories, perhaps they should have their
  735.      contents listed rather than being mentioned here as files.  */
  736.  
  737.   if (trace_dirs)
  738.     extract_dirs_from_files (name, 1, thispend);
  739.  
  740.   if (print_dir_name)
  741.   {
  742.     if (realname)
  743.       printf ("%s:\n", realname);
  744.     else
  745.       printf ("%s:\n", name);
  746.   }
  747.  
  748. #ifndef PCDOS
  749.   if (format == long_format || print_block_size)
  750.     printf ("total %u\n", total_blocks);
  751. #endif
  752.  
  753.   if (files_index)
  754.     print_current_files ();
  755.  
  756. #ifdef PCDOS
  757.   if(format == long_format || format == many_per_line || print_block_size)
  758.   {
  759.     printf ("\t%d file(s)\t", files_index);
  760.     if(print_block_size)
  761.       printf ("%lu blocks allocated\n", total_blocks);
  762.     else
  763.       printf ("%lu blocks used\n", total_blocks);
  764.   }
  765. #endif
  766.  
  767.   if (pending_dirs)
  768.     putchar ('\n');
  769. }
  770.  
  771. /* Add `pattern' to the list of patterns for which files that match are
  772.    listed.  */
  773.  
  774. void
  775. add_list_pattern (pattern)
  776.      char *pattern;
  777.  
  778. {
  779.   register struct ignore_pattern *list;
  780.  
  781.   list = (struct ignore_pattern *) xmalloc (sizeof (struct ignore_pattern));
  782.   list->pattern = pattern;
  783.   /* Add it to the head of the linked list. */
  784.   list->next = pending_dirs->list_patterns;
  785.   pending_dirs->list_patterns = list;
  786. }
  787. /* Add `pattern' to the list of patterns for which files that match are
  788.    not listed.  */
  789.  
  790. void
  791. add_ignore_pattern (pattern)
  792.      char *pattern;
  793.  
  794. {
  795.   register struct ignore_pattern *ignore;
  796.  
  797.   ignore = (struct ignore_pattern *) xmalloc (sizeof (struct ignore_pattern));
  798.   ignore->pattern = pattern;
  799.   /* Add it to the head of the linked list. */
  800.   ignore->next = ignore_patterns;
  801.   ignore_patterns = ignore;
  802. }
  803.  
  804. /* Return nonzero if the file in `next' should be listed. */
  805.  
  806. int
  807. file_interesting (dirp, thispend)
  808.      register CFDIRENT *dirp;
  809. register struct pending *thispend;
  810.  
  811. {
  812.   register struct ignore_pattern *ignore;
  813.  
  814.   /* exclude files which match the ignore_pattern list */
  815.   for (ignore = ignore_patterns; ignore; ignore = ignore->next)
  816.     if (glob_match (ignore->pattern, dirp->d_name, 1))
  817.       return 0;
  818.  
  819.   /* include files which match the list_pattern list */
  820.  
  821.   for (ignore = thispend->list_patterns; ignore; ignore = ignore->next)
  822.   {
  823.     if (glob_match (ignore->pattern, dirp->d_name, 1))
  824.       goto file_maybe_ok;
  825.   }
  826.   if(thispend->list_patterns) return 0;
  827.  
  828. file_maybe_ok:
  829.   if (really_all_files
  830.       || dirp->d_name[0] != '.'
  831.       || (all_files
  832.       && dirp->d_name[1] != '\0'
  833.       && (dirp->d_name[1] != '.' || dirp->d_name[2] != '\0')))
  834.     return 1;
  835.  
  836.   return 0;
  837. }
  838.  
  839. /* Enter and remove entries in the table `files'.  */
  840.  
  841. /* Empty the table of files. */
  842.  
  843. void
  844. clear_files ()
  845.  
  846. {
  847.   register int i;
  848.  
  849.   for (i = 0; i < files_index; i++)
  850.   {
  851.     free (files[i].name);
  852.     if (files[i].linkname)
  853.       free (files[i].linkname);
  854.   }
  855.  
  856.   files_index = 0;
  857.   block_size_size = 3;
  858. }
  859.  
  860. /* Add a file to the current table of files.
  861.    Verify that the file exists, and print an error message if it does not.
  862.    Return the number of blocks that the file occupies.  */
  863.  
  864. long
  865. gobble_file (name, explicit_arg, dirname, dirp)
  866.    char *name;
  867. int explicit_arg;
  868. char *dirname;
  869. CFDIRENT *dirp;
  870.  
  871. {
  872.   long blocks;
  873.   register int val;
  874.   register char *path;
  875.   struct file *f;
  876.   int printable;
  877.  
  878.   if (files_index == nfiles)
  879.   {
  880.     nfiles *= 2;
  881.     files = (struct file *) xrealloc (files, sizeof (struct file) * nfiles);
  882.   }
  883.  
  884.   f = &files[files_index];
  885.   f->linkname = NULL;
  886.   f->linkmode = 0;
  887.   if(!dirp)
  888.          printable = 1;
  889.   else printable = is_printable(name, dirp->d_namlen);    
  890.  
  891.   if (explicit_arg && printable && if_pattern(name))
  892.   {/* The shell passed a pattern which needs globbing locally */
  893.     char ch, *pat;
  894.  
  895.     if(path = rindex(name, '/'))
  896.     {
  897.       pat = path+1;
  898.       if(path == name || path[-1] == ':')
  899.         ++path;
  900.  
  901.       ch = *path;
  902.       *path = '\0';
  903.       if( ((pending_dirs) ? (strcmp(pending_dirs->name, name)) : 1))
  904.         queue_directory (name, NULL, NULL);
  905.       *path = ch;
  906.       add_list_pattern(pat);
  907.       return 0;
  908.     }
  909.     if(name[1] == ':')
  910.     {/* e.g. b:*.h */
  911.       ch = name[2];
  912.       name[2] = '\0';
  913.       if( ((pending_dirs) ? (strcmp(pending_dirs->name, name)) : 1))
  914.         queue_directory (name, NULL, NULL);
  915.       name[2] = ch;
  916.       add_list_pattern(&name[2]);
  917.       return 0;
  918.     }
  919.     else
  920.     {
  921.       if(!pending_dirs)
  922.         queue_directory ("./", NULL, NULL);
  923.       add_list_pattern(name);
  924.       return 0;
  925.     }
  926.     return 0;
  927.   }
  928.   blocks = 0;
  929.   if (explicit_arg || format_needs_stat)
  930.   {
  931.   LSTAT *sp = &f->stats;
  932.     if(dirp)
  933.     {
  934.         sp->st_mode = dirp->d_mode;
  935.         sp->st_size = dirp->d_bytesused;
  936.         sp->st_alloc = dirp->d_bytesalloc;
  937.         sp->st_mtime = dirp->d_mtime;
  938.         sp->st_ctime = dirp->d_ctime;
  939.         sp->st_atime = sp->st_mtime;
  940.         sp->st_ino = dirp->d_ino;
  941.         if(sp->st_mode & (M_HASHDIR|M_TREEDIR))
  942.              sp->st_mode |= S_IFDIR;
  943.         else sp->st_mode |= S_IFREG;
  944.     } else {
  945.     CFSTAT s;
  946.         cfstat(name, &s);
  947.         sp->st_mode = s.st_mode;
  948.         sp->st_size = s.st_size;
  949.         sp->st_alloc = s.st_size;
  950.         sp->st_mtime = s.st_mtime;
  951.         sp->st_ctime = s.st_ctime;
  952.         sp->st_atime = s.st_atime;
  953.         sp->st_ino = s.st_ino;
  954.         if(sp->st_mode & (M_HASHDIR|M_TREEDIR))
  955.              sp->st_mode |= S_IFDIR;
  956.         else sp->st_mode |= S_IFREG;
  957.     }
  958. settype:
  959.     switch (sp->st_mode & S_IFMT)
  960.     {
  961.  
  962.       case S_IFDIR:
  963.         if (explicit_arg && !immediate_dirs)
  964.           f->filetype = arg_directory;
  965.         else
  966.           f->filetype = directory;
  967.         break;
  968.  
  969.       default:
  970.         f->filetype = normal;
  971.         break;
  972.     }
  973.  
  974.     blocks = (long)convert_blocks(ST_NBLOCKS(sp), kilobyte_blocks);
  975.  
  976.     if(blocks >= 1000 && block_size_size < 4)
  977.       block_size_size = 4;
  978.     if(blocks >= 10000 && block_size_size < 5)
  979.       block_size_size = 5;
  980.     if(blocks >= 100000 && block_size_size < 6)
  981.       block_size_size = 6;
  982.     if(blocks >= 1000000 && block_size_size < 7)
  983.       block_size_size = 7;
  984.   }
  985.   if(dirp)
  986.   {
  987.       if(is_printable(dirp->d_name, dirp->d_namlen))
  988.       {
  989.           f->name = xmalloc(dirp->d_namlen+1);
  990.           memcpy(f->name, dirp->d_name, dirp->d_namlen+1);
  991.           f->namlen = dirp->d_namlen;
  992.       } else {/* print a tidbit of the key, in hex */
  993.          f->name = xmalloc(16);
  994.          f->namlen = cfsprintf(f->name, "0x%x", *((long *)dirp->d_name));
  995.       }
  996.   } else {
  997.       f->namlen = strlen(name);
  998.       f->name = xmalloc(f->namlen+1);
  999.       strcpy(f->name, name);
  1000.   }
  1001.   files_index++;
  1002.  
  1003.   return blocks;
  1004. }
  1005.  
  1006.  
  1007. /* Remove any entries from `files' that are for directories,
  1008.    and queue them to be listed as directories instead.
  1009.    `dirname' is the prefix to prepend to each dirname
  1010.    to make it correct relative to ls's working dir.
  1011.    `recursive' is nonzero if we should not treat `.' and `..' as dirs.
  1012.    This is desirable when processing directories recursively.  */
  1013.  
  1014. void
  1015. extract_dirs_from_files (dirname, recursive, thispend)
  1016.      char *dirname;
  1017. int recursive;
  1018. struct pending *thispend;
  1019.  
  1020. {
  1021.   register int i, j;
  1022.   register char *path;
  1023.   int dirlen;
  1024.  
  1025.   dirlen = strlen (dirname) + 2;
  1026.   /* Queue the directories last one first, because queueing reverses the
  1027.      order.  */
  1028.   for (i = files_index - 1; i >= 0; i--)
  1029.     if ((files[i].filetype == directory || files[i].filetype == arg_directory)
  1030.   && (!recursive || is_not_dot_or_dotdot (files[i].name)))
  1031.     {
  1032.       if (files[i].name[0] == '/' || dirname[0] == 0)
  1033.       {
  1034.         queue_directory (files[i].name, files[i].linkname, thispend);
  1035.       }
  1036.       else
  1037.       {
  1038.         path = (char *) xmalloc (strlen (files[i].name) + dirlen);
  1039.         attach (path, dirname, files[i].name);
  1040.         queue_directory (path, files[i].linkname, thispend);
  1041.         free (path);
  1042.       }
  1043.       if (  files[i].filetype == arg_directory
  1044.         || (files[i].filetype == directory && thispend->list_patterns))
  1045.         free (files[i].name);
  1046.     }
  1047.  
  1048.   /* Now delete the directories from the table, compacting all the remaining
  1049.      entries.  */
  1050.  
  1051.   for (i = 0, j = 0; i < files_index; i++)
  1052.     if (  !(files[i].filetype == arg_directory
  1053.          || (files[i].filetype == directory && thispend->list_patterns)))
  1054.       files[j++] = files[i];
  1055.   files_index = j;
  1056. }
  1057.  
  1058. /* Return non-zero if `name' doesn't end in `.' or `..'
  1059.    This is so we don't try to recurse on `././././. ...' */
  1060.  
  1061. int
  1062. is_not_dot_or_dotdot (name)
  1063.      char *name;
  1064.  
  1065. {
  1066.   char *t;
  1067.  
  1068.   t = rindex (name, '/');
  1069.   if (t)
  1070.     name = t + 1;
  1071.  
  1072.   if (name[0] == '.'
  1073.       && (name[1] == '\0'
  1074.     || (name[1] == '.' && name[2] == '\0')))
  1075.     return 0;
  1076.  
  1077.   return 1;
  1078. }
  1079.  
  1080. /* Sort the files now in the table.  */
  1081.  
  1082. void
  1083. sort_files ()
  1084.  
  1085. {
  1086.   int (*func) ();
  1087.  
  1088.   switch (sort_type)
  1089.   {
  1090.     case sort_none:
  1091.       return;
  1092.     case sort_time:
  1093.       switch (time_type)
  1094.       {
  1095.         case time_ctime:
  1096.           func = sort_reverse ? rev_cmp_ctime : compare_ctime;
  1097.           break;
  1098.         case time_mtime:
  1099.           func = sort_reverse ? rev_cmp_mtime : compare_mtime;
  1100.           break;
  1101.         case time_atime:
  1102.           func = sort_reverse ? rev_cmp_atime : compare_atime;
  1103.           break;
  1104.       }
  1105.       break;
  1106.     case sort_name:
  1107.       func = sort_reverse ? rev_cmp_name : compare_name;
  1108.       break;
  1109.     case sort_extension:
  1110.       func = sort_reverse ? rev_cmp_extension : compare_extension;
  1111.       break;
  1112.     case sort_size:
  1113.       func = sort_reverse ? rev_cmp_size : compare_size;
  1114.       break;
  1115.   }
  1116.  
  1117.   qsort (files, files_index, sizeof (struct file), func);
  1118. }
  1119.  
  1120. /* Comparison routines for sorting the files. */
  1121.  
  1122. int
  1123. compare_ctime (file1, file2)
  1124.      struct file *file1, *file2;
  1125.  
  1126. {
  1127.   return longdiff (file2->stats.st_ctime, file1->stats.st_ctime);
  1128. }
  1129.  
  1130. int
  1131. rev_cmp_ctime (file2, file1)
  1132.      struct file *file1, *file2;
  1133.  
  1134. {
  1135.   return longdiff (file2->stats.st_ctime, file1->stats.st_ctime);
  1136. }
  1137.  
  1138. int
  1139. compare_mtime (file1, file2)
  1140.      struct file *file1, *file2;
  1141.  
  1142. {
  1143.   return longdiff (file2->stats.st_mtime, file1->stats.st_mtime);
  1144. }
  1145.  
  1146. int
  1147. rev_cmp_mtime (file2, file1)
  1148.      struct file *file1, *file2;
  1149.  
  1150. {
  1151.   return longdiff (file2->stats.st_mtime, file1->stats.st_mtime);
  1152. }
  1153.  
  1154. int
  1155. compare_atime (file1, file2)
  1156.      struct file *file1, *file2;
  1157.  
  1158. {
  1159.   return longdiff (file2->stats.st_atime, file1->stats.st_atime);
  1160. }
  1161.  
  1162. int
  1163. rev_cmp_atime (file2, file1)
  1164.      struct file *file1, *file2;
  1165.  
  1166. {
  1167.   return longdiff (file2->stats.st_atime, file1->stats.st_atime);
  1168. }
  1169.  
  1170. int
  1171. compare_size (file1, file2)
  1172.      struct file *file1, *file2;
  1173.  
  1174. {
  1175.   return longdiff (file2->stats.st_size, file1->stats.st_size);
  1176. }
  1177.  
  1178. int
  1179. rev_cmp_size (file2, file1)
  1180.      struct file *file1, *file2;
  1181.  
  1182. {
  1183.   return longdiff (file2->stats.st_size, file1->stats.st_size);
  1184. }
  1185.  
  1186. int
  1187. compare_name (file1, file2)
  1188.      struct file *file1, *file2;
  1189.  
  1190. {
  1191.   return strcmp (file1->name, file2->name);
  1192. }
  1193.  
  1194. int
  1195. rev_cmp_name (file2, file1)
  1196.      struct file *file1, *file2;
  1197.  
  1198. {
  1199.   return strcmp (file1->name, file2->name);
  1200. }
  1201.  
  1202. /* Compare file extensions.  Files with no extension are `smallest'.
  1203.    If extensions are the same, compare by filenames instead. */
  1204.  
  1205. int
  1206. compare_extension (file1, file2)
  1207.      struct file *file1, *file2;
  1208.  
  1209. {
  1210.   register char *base1, *base2;
  1211.   register int cmp;
  1212.  
  1213.   base1 = rindex (file1->name, '.');
  1214.   base2 = rindex (file2->name, '.');
  1215.   if (base1 == NULL && base2 == NULL)
  1216.     return strcmp (file1->name, file2->name);
  1217.   if (base1 == NULL)
  1218.     return -1;
  1219.   if (base2 == NULL)
  1220.     return 1;
  1221.   cmp = strcmp (base1, base2);
  1222.   if (cmp == 0)
  1223.     return strcmp (file1->name, file2->name);
  1224.   return cmp;
  1225. }
  1226.  
  1227. int
  1228. rev_cmp_extension (file2, file1)
  1229.      struct file *file1, *file2;
  1230.  
  1231. {
  1232.   register char *base1, *base2;
  1233.   register int cmp;
  1234.  
  1235.   base1 = rindex (file1->name, '.');
  1236.   base2 = rindex (file2->name, '.');
  1237.   if (base1 == NULL && base2 == NULL)
  1238.     return strcmp (file1->name, file2->name);
  1239.   if (base1 == NULL)
  1240.     return -1;
  1241.   if (base2 == NULL)
  1242.     return 1;
  1243.   cmp = strcmp (base1, base2);
  1244.   if (cmp == 0)
  1245.     return strcmp (file1->name, file2->name);
  1246.   return cmp;
  1247. }
  1248.  
  1249. /* List all the files now in the table.  */
  1250.  
  1251. void
  1252. print_current_files ()
  1253.  
  1254. {
  1255.   register int i;
  1256.  
  1257.   switch (format)
  1258.   {
  1259.     case one_per_line:
  1260.       for (i = 0; i < files_index; i++)
  1261.       {
  1262.         print_file_name_and_frills (files + i);
  1263.         putchar ('\n');
  1264.       }
  1265.       break;
  1266.  
  1267.     case many_per_line:
  1268.       print_many_per_line ();
  1269.       break;
  1270.  
  1271.     case horizontal:
  1272.       print_horizontal ();
  1273.       break;
  1274.  
  1275.     case with_commas:
  1276.       print_with_commas ();
  1277.       break;
  1278.  
  1279.     case long_format:
  1280.       for (i = 0; i < files_index; i++)
  1281.       {
  1282.         print_long_format (files + i);
  1283.         putchar ('\n');
  1284.       }
  1285.       break;
  1286.   }
  1287. }
  1288.  
  1289. void
  1290. print_long_format (f)
  1291.      struct file *f;
  1292.  
  1293. {
  1294.   char modebuf[20];
  1295.   char timebuf[40];
  1296.   long when;
  1297.   unsigned long mode = f->stats.st_mode;
  1298.  
  1299.   if(mode & M_CHUNK)
  1300.       strcpy(modebuf, "Chunk");
  1301.   else if(mode & M_VALUE)
  1302.     strcpy(modebuf, "Value");
  1303.   else if(mode & (M_TREEDIR|M_HASHDIR))
  1304.     strcpy(modebuf, "Node ");
  1305.   else modebuf[0] = 0;
  1306.   switch (time_type)
  1307.   {
  1308.     case time_ctime:
  1309.       when = f->stats.st_ctime;
  1310.       break;
  1311.     case time_mtime:
  1312.       when = f->stats.st_mtime;
  1313.       break;
  1314.     case time_atime:
  1315.       when = f->stats.st_atime;
  1316.       break;
  1317.   }
  1318.   if(when > 0)
  1319.   {
  1320.       strcpy (timebuf, (char *)ctime (&when));
  1321.       if (current_time - when > 6L * 30L * 24L * 60L * 60L
  1322.           || current_time - when < 0L)
  1323.       {
  1324.           /* The file is fairly old or in the future.
  1325.        POSIX says the cutoff is 6 months old;
  1326.        approximate this by 6*30 days.
  1327.        Show the year instead of the time of day.  */
  1328.         strcpy (timebuf + 11, timebuf + 19);
  1329.       }
  1330.   } else strcpy (timebuf, "      No Date   ");
  1331.   timebuf[16] = 0;
  1332.  
  1333.   if (print_inode)
  1334. #ifndef PCDOS
  1335.     printf ("%6u ", f->stats.st_ino);
  1336. #else
  1337.     printf ("%5u ", f->stats.st_ino);
  1338. #endif
  1339.   if (print_block_size)
  1340.   {
  1341.     printf ("%*u ", block_size_size, convert_blocks (ST_NBLOCKS (&f->stats),
  1342.                kilobyte_blocks));/* used blocks */
  1343.   }
  1344.  
  1345.   printf("%s ", modebuf);
  1346.  
  1347.   printf ("%8lu ", f->stats.st_size);
  1348.  
  1349.   printf ("%s ", timebuf + 4);
  1350.  
  1351.   print_name_with_quoting (f->name);
  1352.  
  1353.   if (f->filetype == symbolic_link)
  1354.   {
  1355.  
  1356.     if (f->linkname)
  1357.     {
  1358.       fputs (" -> ", stdout);
  1359.       print_name_with_quoting (f->linkname);
  1360.       if (indicator_style != none)
  1361.         print_type_indicator (f->linkmode);
  1362.     }
  1363.  
  1364.   }
  1365.   else if (indicator_style != none)
  1366.     print_type_indicator (f->stats.st_mode);
  1367.  
  1368. }
  1369.  
  1370. void
  1371. print_name_with_quoting (p)
  1372.      register char *p;
  1373.  
  1374. {
  1375.   register unsigned char c;
  1376.  
  1377.   if (quote_as_string)
  1378.     putchar ('"');
  1379.  
  1380.   while (c = *p++)
  1381.   {
  1382.     if (quote_funny_chars)
  1383.     {
  1384.       switch (c)
  1385.       {
  1386.         case '\\':
  1387.           printf ("\\\\");
  1388.           break;
  1389.  
  1390.         case '\n':
  1391.           printf ("\\n");
  1392.           break;
  1393.  
  1394.         case '\b':
  1395.           printf ("\\b");
  1396.           break;
  1397.  
  1398.         case '\r':
  1399.           printf ("\\r");
  1400.           break;
  1401.  
  1402.         case '\t':
  1403.           printf ("\\t");
  1404.           break;
  1405.  
  1406.         case '\f':
  1407.           printf ("\\f");
  1408.           break;
  1409.  
  1410.         case ' ':
  1411.           printf ("\\ ");
  1412.           break;
  1413.  
  1414.         case '"':
  1415.           printf ("\\\"");
  1416.           break;
  1417.  
  1418.         default:
  1419.           if (c > 040 && c < 0177)
  1420.             putchar (c);
  1421.           else
  1422.             printf ("\\%03o", (unsigned int) c);
  1423.       }
  1424.     }
  1425.     else
  1426.     {
  1427.       if (c >= 040 && c < 0177)
  1428.         putchar (c);
  1429.       else if (!qmark_funny_chars)
  1430.         putchar (c);
  1431.       else
  1432.         putchar ('?');
  1433.     }
  1434.   }
  1435.  
  1436.   if (quote_as_string)
  1437.     putchar ('"');
  1438. }
  1439.  
  1440. /* Print the file name of `f' with appropriate quoting.
  1441.    Also print file size, inode number, and filetype indicator character,
  1442.    as requested by switches.  */
  1443.  
  1444. void
  1445. print_file_name_and_frills (f)
  1446.      struct file *f;
  1447.  
  1448. {
  1449.   if (print_inode)
  1450. #ifndef PCDOS
  1451.     printf ("%6u ", f->stats.st_ino);
  1452. #else
  1453.     printf ("%5u ", f->stats.st_ino);
  1454. #endif
  1455.   if (print_block_size)
  1456.   {
  1457.     printf ("%*u ",block_size_size, convert_blocks (ST_NBLOCKS (&f->stats),
  1458.                  kilobyte_blocks));/* used blocks */
  1459.   }
  1460. #ifdef PCDOS
  1461.   if(format == many_per_line)
  1462.   {
  1463.     strupr(f->name);
  1464.     if((f->stats.st_mode & S_IFMT) == S_IFDIR)
  1465.       putchar('[');
  1466.   }
  1467. #endif
  1468.  
  1469.   print_name_with_quoting (f->name);
  1470.  
  1471. #ifdef PCDOS
  1472.   if(format == many_per_line)
  1473.     if((f->stats.st_mode & S_IFMT) == S_IFDIR)
  1474.       putchar(']');
  1475. #endif
  1476.  
  1477.   if (indicator_style != none)
  1478.     print_type_indicator (f->stats.st_mode);
  1479. }
  1480.  
  1481. void
  1482. print_type_indicator (mode)
  1483.      unsigned int mode;
  1484.  
  1485. {
  1486.   switch (mode & S_IFMT)
  1487.   {
  1488.     case S_IFDIR:
  1489. #ifdef PCDOS
  1490.       if(format != many_per_line)
  1491. #endif
  1492.         putchar ('/');
  1493.       break;
  1494.  
  1495. #ifdef S_IFLNK
  1496.     case S_IFLNK:
  1497.       putchar ('@');
  1498.       break;
  1499. #endif
  1500.  
  1501. #ifdef S_IFIFO
  1502.     case S_IFIFO:
  1503.       putchar ('|');
  1504.       break;
  1505. #endif
  1506.  
  1507. #ifdef S_IFSOCK
  1508.     case S_IFSOCK:
  1509.       putchar ('=');
  1510.       break;
  1511. #endif
  1512.  
  1513.     case S_IFREG:
  1514.       if (indicator_style == all
  1515.     && (mode & (S_IEXEC | S_IEXEC >> 3 | S_IEXEC >> 6)))
  1516.         putchar ('*');
  1517.       break;
  1518.   }
  1519. }
  1520.  
  1521. int
  1522. length_of_file_name_and_frills (f)
  1523.      struct file *f;
  1524.  
  1525. {
  1526.   register char *p = f->name;
  1527.   register char c;
  1528.   register int len = 0;
  1529.   unsigned filetype = f->stats.st_mode & S_IFMT;
  1530.  
  1531.   if (print_inode)
  1532.   {
  1533. #ifndef PCDOS
  1534.     len += 7;
  1535. #else
  1536.     len += 6;
  1537. #endif
  1538.   }
  1539.  
  1540.   if (print_block_size)
  1541.     len += 1 + block_size_size;
  1542.  
  1543.   if (quote_as_string)
  1544.     len += 2;
  1545.  
  1546.   while (c = *p++)
  1547.   {
  1548.     if (quote_funny_chars)
  1549.     {
  1550.       switch (c)
  1551.       {
  1552.         case '\\':
  1553.         case '\n':
  1554.         case '\b':
  1555.         case '\r':
  1556.         case '\t':
  1557.         case '\f':
  1558.         case ' ':
  1559.           len += 2;
  1560.           break;
  1561.  
  1562.         case '"':
  1563.           if (quote_as_string)
  1564.             len += 2;
  1565.           else
  1566.             len += 1;
  1567.           break;
  1568.  
  1569.         default:
  1570.           if (c >= 040 && c < 0177)
  1571.             len += 1;
  1572.           else
  1573.             len += 4;
  1574.       }
  1575.     }
  1576.     else
  1577.       len += 1;
  1578.   }
  1579.  
  1580.   if (indicator_style != none)
  1581.   {
  1582.     if (filetype == S_IFREG)
  1583.     {
  1584.       if (indicator_style == all
  1585.         && (f->stats.st_mode & (S_IEXEC | S_IEXEC >> 3 | S_IEXEC >> 6)))
  1586.         len += 1;
  1587.     }
  1588.     else if (filetype & S_IFDIR
  1589. #ifdef S_IFLNK
  1590.          || filetype == S_IFLNK
  1591. #endif
  1592. #ifdef S_IFIFO
  1593.          || filetype == S_IFIFO
  1594. #endif
  1595. #ifdef S_IFSOCK
  1596.          || filetype == S_IFSOCK
  1597. #endif
  1598.       ) len += 1;
  1599.   }
  1600. #ifdef PCDOS
  1601.   if(format == many_per_line)
  1602.   {
  1603.     if(filetype == S_IFDIR)
  1604.     {
  1605.       len += 2;
  1606.       if(indicator_style != none) --len;
  1607.     }
  1608.   }
  1609. #endif
  1610.   return len;
  1611. }
  1612.  
  1613. void
  1614. print_many_per_line ()
  1615.  
  1616. {
  1617.   int filesno;      /* Index into files. */
  1618.   int row;      /* Current row. */
  1619.   int max_name_length;    /* Length of longest file name + frills. */
  1620.   int name_length;    /* Length of each file name + frills. */
  1621.   int pos;      /* Current character column. */
  1622.   int cols;     /* Number of files across. */
  1623.   int rows;     /* Maximum number of files down. */
  1624.  
  1625.   /* Compute the maximum file name length.  */
  1626.   max_name_length = 0;
  1627.   for (filesno = 0; filesno < files_index; filesno++)
  1628.   {
  1629.     name_length = length_of_file_name_and_frills (files + filesno);
  1630.     if (name_length > max_name_length)
  1631.       max_name_length = name_length;
  1632.   }
  1633.  
  1634.   /* Allow at least two spaces between names.  */
  1635.   max_name_length += 2;
  1636.  
  1637.   /* Calculate the maximum number of columns that will fit. */
  1638.   cols = line_length / max_name_length;
  1639.   if (cols == 0)
  1640.     cols = 1;
  1641.   /* Calculate the number of rows that will be in each column except possibly
  1642.      for a short column on the right. */
  1643.   rows = files_index / cols + (files_index % cols != 0);
  1644.   /* Recalculate columns based on rows. */
  1645.   cols = files_index / rows + (files_index % rows != 0);
  1646.  
  1647.   for (row = 0; row < rows; row++)
  1648.   {
  1649.     filesno = row;
  1650.     pos = 0;
  1651.       /* Print the next row.  */
  1652.     while (1)
  1653.     {
  1654.       print_file_name_and_frills (files + filesno);
  1655.       name_length = length_of_file_name_and_frills (files + filesno);
  1656.  
  1657.       filesno += rows;
  1658.       if (filesno >= files_index)
  1659.         break;
  1660.  
  1661.       indent (pos + name_length, pos + max_name_length);
  1662.       pos += max_name_length;
  1663.     }
  1664.     putchar ('\n');
  1665.   }
  1666. }
  1667.  
  1668. void
  1669. print_horizontal ()
  1670.  
  1671. {
  1672.   int filesno;
  1673.   int max_name_length;
  1674.   int name_length;
  1675.   int cols;
  1676.   int pos;
  1677.  
  1678.   /* Compute the maximum file name length.  */
  1679.   max_name_length = 0;
  1680.   for (filesno = 0; filesno < files_index; filesno++)
  1681.   {
  1682.     name_length = length_of_file_name_and_frills (files + filesno);
  1683.     if (name_length > max_name_length)
  1684.       max_name_length = name_length;
  1685.   }
  1686.  
  1687.   /* Allow two spaces between names.  */
  1688.   max_name_length += 2;
  1689.  
  1690.   cols = line_length / max_name_length;
  1691.   if (cols == 0)
  1692.     cols = 1;
  1693.  
  1694.   pos = 0;
  1695.   name_length = 0;
  1696.  
  1697.   for (filesno = 0; filesno < files_index; filesno++)
  1698.   {
  1699.     if (filesno != 0)
  1700.     {
  1701.       if (filesno % cols == 0)
  1702.       {
  1703.         putchar ('\n');
  1704.         pos = 0;
  1705.       }
  1706.       else
  1707.       {
  1708.         indent (pos + name_length, pos + max_name_length);
  1709.         pos += max_name_length;
  1710.       }
  1711.     }
  1712.  
  1713.     print_file_name_and_frills (files + filesno);
  1714.  
  1715.     name_length = length_of_file_name_and_frills (files + filesno);
  1716.   }
  1717.   putchar ('\n');
  1718. }
  1719.  
  1720. void
  1721. print_with_commas ()
  1722.  
  1723. {
  1724.   int filesno;
  1725.   int pos, old_pos;
  1726.  
  1727.   pos = 0;
  1728.  
  1729.   for (filesno = 0; filesno < files_index; filesno++)
  1730.   {
  1731.     old_pos = pos;
  1732.  
  1733.     pos += length_of_file_name_and_frills (files + filesno);
  1734.     if (filesno + 1 < files_index)
  1735.       pos += 2;   /* For the comma and space */
  1736.  
  1737.     if (old_pos != 0 && pos >= line_length)
  1738.     {
  1739.       putchar ('\n');
  1740.       pos -= old_pos;
  1741.     }
  1742.  
  1743.     print_file_name_and_frills (files + filesno);
  1744.     if (filesno + 1 < files_index)
  1745.     {
  1746.       putchar (',');
  1747.       putchar (' ');
  1748.     }
  1749.   }
  1750.   putchar ('\n');
  1751. }
  1752.  
  1753. #ifndef PCDOS
  1754. struct userid
  1755. {
  1756.   unsigned short uid;
  1757.   char *name;
  1758.   struct userid *next;
  1759. };
  1760.  
  1761. struct userid *user_alist;
  1762.  
  1763. /* Translate `uid' to a login name, with cache.  */
  1764.  
  1765. char *
  1766. getuser (uid)
  1767.      unsigned short uid;
  1768.  
  1769. {
  1770.   register struct userid *tail;
  1771.   struct passwd *pwent;
  1772.   char usernum_string[20];
  1773.  
  1774.   for (tail = user_alist; tail; tail = tail->next)
  1775.     if (tail->uid == uid)
  1776.       return tail->name;
  1777.  
  1778.   pwent = getpwuid (uid);
  1779.   tail = (struct userid *) xmalloc (sizeof (struct userid));
  1780.   tail->uid = uid;
  1781.   tail->next = user_alist;
  1782.   if (pwent == NULL)
  1783.   {
  1784.     sprintf (usernum_string, "%u", (unsigned short) uid);
  1785.     tail->name = copystring (usernum_string);
  1786.   }
  1787.   else
  1788.     tail->name = copystring (pwent->pw_name);
  1789.   user_alist = tail;
  1790.   return tail->name;
  1791. }
  1792.  
  1793. /* We use the same struct as for userids.  */
  1794. struct userid *group_alist;
  1795.  
  1796. /* Translate `gid' to a group name, with cache.  */
  1797.  
  1798. char *
  1799. getgroup (gid)
  1800.      unsigned short gid;
  1801.  
  1802. {
  1803.   register struct userid *tail;
  1804.   struct group *grent;
  1805.   char groupnum_string[20];
  1806.  
  1807.   for (tail = group_alist; tail; tail = tail->next)
  1808.     if (tail->uid == gid)
  1809.       return tail->name;
  1810.  
  1811.   grent = getgrgid (gid);
  1812.   tail = (struct userid *) xmalloc (sizeof (struct userid));
  1813.   tail->uid = gid;
  1814.   tail->next = group_alist;
  1815.   if (grent == NULL)
  1816.   {
  1817.     sprintf (groupnum_string, "%u", (unsigned int) gid);
  1818.     tail->name = copystring (groupnum_string);
  1819.   }
  1820.   else
  1821.     tail->name = copystring (grent->gr_name);
  1822.   group_alist = tail;
  1823.   return tail->name;
  1824. }
  1825. #endif
  1826. /* Assuming cursor is at position `from', indent up to position `to'.  */
  1827.  
  1828. void
  1829. indent (from, to)
  1830.      int from, to;
  1831.  
  1832. {
  1833.   while (from < to)
  1834.   {
  1835.     if (to / tabsize > from / tabsize)
  1836.     {
  1837.       putchar ('\t');
  1838.       from += tabsize - from % tabsize;
  1839.     }
  1840.     else
  1841.     {
  1842.       putchar (' ');
  1843.       from++;
  1844.     }
  1845.   }
  1846. }
  1847.  
  1848. /* Low level subroutines of general use,
  1849.    not specifically related to the task of listing a directory.  */
  1850.  
  1851. char *
  1852. xrealloc (obj, size)
  1853. void *obj;
  1854. int size;
  1855.  
  1856. {
  1857.   char *val = realloc (obj, size);
  1858.  
  1859.   if (!val)
  1860.     error (1, 0, "virtual memory exhausted");
  1861.  
  1862.   return val;
  1863. }
  1864.  
  1865. char *
  1866. xmalloc (size)
  1867.      int size;
  1868.  
  1869. {
  1870.   char *val = malloc (size);
  1871.  
  1872.   if (!val)
  1873.     error (1, 0, "virtual memory exhausted");
  1874.  
  1875.   return val;
  1876. }
  1877.  
  1878. /* Return a newly allocated copy of `string'. */
  1879.  
  1880. char *
  1881. copystring (string)
  1882.      char *string;
  1883.  
  1884. {
  1885.   return strcpy ((char *) xmalloc (strlen (string) + 1), string);
  1886. }
  1887.  
  1888. /* Put `dirname/name' into `dest', handling `.' and `/' properly. */
  1889.  
  1890. void
  1891. attach (dest, dirname, name)
  1892.      char *dest, *dirname, *name;
  1893.  
  1894. {
  1895.   char *dirnamep = dirname;
  1896.  
  1897.   /* Copy dirname if it is not ".". */
  1898.   if (dirname[0] != '.' || dirname[1] != 0)
  1899.   {
  1900.     while (*dirnamep)
  1901.       *dest++ = *dirnamep++;
  1902.       /* Add '/' if `dirname' doesn't already end with it. */
  1903.     if (dirnamep > dirname && (dirnamep[-1] != '/'
  1904. #ifdef PCDOS
  1905.           && dirnamep[-1] != ':'
  1906. #endif
  1907.           ))
  1908.       *dest++ = '/';
  1909.   }
  1910.   while (*name)
  1911.     *dest++ = *name++;
  1912.   *dest = 0;
  1913. }
  1914.  
  1915. /* Check for a globbing pattern in an explicit argument, the shell may
  1916.   have passed it along, always for PCDOS. */
  1917.  
  1918. int
  1919. if_pattern(name)
  1920. register char *name;
  1921.  
  1922. {
  1923.   register char ch;
  1924.   while (ch = *name++)
  1925.     if (ch == '*' || ch == '?' || ch == '[')
  1926.       return 1;
  1927.   return 0;
  1928. }
  1929. #ifdef PCDOS
  1930. void lose_backslashes(char *path)
  1931.  
  1932. {
  1933.   while(*path)
  1934.   {
  1935.     if(*path == '\\') *path = '/';
  1936.     ++path;
  1937.   }
  1938. }
  1939. #endif
  1940.  
  1941. void
  1942. usage ()
  1943.  
  1944. {
  1945.   fprintf (stdout, "\
  1946. Usage: ls [-abdgiklnpqrstxABCFNQRSUX1] [path...]\n");
  1947.   fprintf (stdout, "\n\
  1948.   Switch-------------------Meaning\n\
  1949.   a, +all                  List all files.\n\
  1950.   b, +escape               Quote nongraphic characters.\n\
  1951.   d, +directory            List directory name, not contents.\n\
  1952.   g,                       Ignored for Unix compatibility.\n\
  1953.   i, +inode                Print index number of each file.\n\
  1954.   k, +kilobytes            Print file sizes in kilobyte blocks.\n\
  1955.   l, +format=long          Print in long format.\n\
  1956.   m, +format=commas        List files horizontally, separated by commas.\n\
  1957.   p                        Put '/' after each directory, if not multi-col.\n\
  1958.   r, +reverse              Sort in reverse order.\n\
  1959.   s, +size                 Print the size of each file in blocks allocated.\n\
  1960.   t, +sort=time            Sort directory contents by timestamp.\n\
  1961.   x, +format=across        Multi-column, sorted horizontally.\n\
  1962.   A, +almost-all           List all files except for '.' and '..'.\n\
  1963.   B, +ignore-backups       Do not list files that end with '~'.\n\
  1964.   C, +format=vertical      Multi-column, sorted vertically.\n\
  1965.   F, +classify             Tag the file type of each file.\n\
  1966.   N, +literal              Do not quote file names.\n\
  1967.   Q, +quote-name           Enclose file names in double quotes.\n\
  1968.   R, +recursive            List the contents of directories recursively.\n\
  1969.   S, +sort=size            Sort directory contents by file size.\n\
  1970.   U, +sort=none            Do not sort directory contents.\n\
  1971.   X, +sort=extension       Sort directory contents by file extension.\n\
  1972.   1, +format=single-column List one file per line.\n\
  1973.   w, +width cols           Assume screen width to be 'cols' wide.\n\
  1974.   T. +tabsize cols         Assume that each tabstop is 'cols' wide.\n\
  1975.   I, +ignore pattern       Do not list files that match 'pattern'.\n");
  1976.  
  1977.   exit (1);
  1978. }
  1979. /* Getopt for GNU.
  1980.    Copyright (C) 1987, 1989, 1990 Free Software Foundation, Inc.
  1981.  
  1982.    This program is free software; you can redistribute it and/or modify
  1983.    it under the terms of the GNU General Public License as published by
  1984.    the Free Software Foundation; either version 1, or (at your option)
  1985.    any later version.
  1986.  
  1987.    This program is distributed in the hope that it will be useful,
  1988.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  1989.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1990.    GNU General Public License for more details.
  1991.  
  1992.    You should have received a copy of the GNU General Public License
  1993.    along with this program; if not, write to the Free Software
  1994.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  1995.  
  1996. #ifdef __STDC__
  1997. #define CONST const
  1998. #else
  1999. #define CONST
  2000. #endif
  2001.  
  2002. /* This version of `getopt' appears to the caller like standard Unix `getopt'
  2003.    but it behaves differently for the user, since it allows the user
  2004.    to intersperse the options with the other arguments.
  2005.  
  2006.    As `getopt' works, it permutes the elements of `argv' so that,
  2007.    when it is done, all the options precede everything else.  Thus
  2008.    all application programs are extended to handle flexible argument order.
  2009.  
  2010.    Setting the environment variable _POSIX_OPTION_ORDER disables permutation.
  2011.    Then the behavior is completely standard.
  2012.  
  2013.    GNU application programs can use a third alternative mode in which
  2014.    they can distinguish the relative order of options and other arguments.  */
  2015.  
  2016.  
  2017. /* For communication from `getopt' to the caller.
  2018.    When `getopt' finds an option that takes an argument,
  2019.    the argument value is returned here.
  2020.    Also, when `ordering' is RETURN_IN_ORDER,
  2021.    each non-option ARGV-element is returned here.  */
  2022.  
  2023. char *optarg = 0;
  2024.  
  2025. /* Index in ARGV of the next element to be scanned.
  2026.    This is used for communication to and from the caller
  2027.    and for communication between successive calls to `getopt'.
  2028.  
  2029.    On entry to `getopt', zero means this is the first call; initialize.
  2030.  
  2031.    When `getopt' returns EOF, this is the index of the first of the
  2032.    non-option elements that the caller should itself scan.
  2033.  
  2034.    Otherwise, `optind' communicates from one call to the next
  2035.    how much of ARGV has been scanned so far.  */
  2036.  
  2037. int optind = 0;
  2038.  
  2039. /* The next char to be scanned in the option-element
  2040.    in which the last option character we returned was found.
  2041.    This allows us to pick up the scan where we left off.
  2042.  
  2043.    If this is zero, or a null string, it means resume the scan
  2044.    by advancing to the next ARGV-element.  */
  2045.  
  2046. static char *nextchar;
  2047.  
  2048. /* Callers store zero here to inhibit the error message
  2049.    for unrecognized options.  */
  2050.  
  2051. int opterr = 1;
  2052.  
  2053. /* Describe how to deal with options that follow non-option ARGV-elements.
  2054.  
  2055.    If the caller did not specify anything,
  2056.    the default is REQUIRE_ORDER if the environment variable
  2057.    _POSIX_OPTION_ORDER is defined, PERMUTE otherwise.
  2058.  
  2059.    REQUIRE_ORDER means don't recognize them as options;
  2060.    stop option processing when the first non-option is seen.
  2061.    This is what Unix does.
  2062.    This mode of operation is selected by either setting the environment
  2063.    variable _POSIX_OPTION_ORDER, or using `+' as the first character
  2064.    of the list of option characters.
  2065.  
  2066.    PERMUTE is the default.  We permute the contents of ARGV as we scan,
  2067.    so that eventually all the non-options are at the end.  This allows options
  2068.    to be given in any order, even with programs that were not written to
  2069.    expect this.
  2070.  
  2071.    RETURN_IN_ORDER is an option available to programs that were written
  2072.    to expect options and other ARGV-elements in any order and that care about
  2073.    the ordering of the two.  We describe each non-option ARGV-element
  2074.    as if it were the argument of an option with character code 1.
  2075.    Using `-' as the first character of the list of option characters
  2076.    selects this mode of operation.
  2077.  
  2078.    The special argument `--' forces an end of option-scanning regardless
  2079.    of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
  2080.    `--' can cause `getopt' to return EOF with `optind' != ARGC.  */
  2081.  
  2082. static enum
  2083. {
  2084.   REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
  2085. } ordering;
  2086.  
  2087. /* Describe the long-named options requested by the application.
  2088.    _GETOPT_LONG_OPTIONS is a vector of `struct option' terminated by an
  2089.    element containing a name which is zero.
  2090.    The field `has_arg' is 1 if the option takes an argument,
  2091.    2 if it takes an optional argument.  */
  2092.  
  2093.  
  2094. CONST struct option *_getopt_long_options;
  2095.  
  2096. int _getopt_long_only = 0;
  2097.  
  2098. /* Index in _GETOPT_LONG_OPTIONS of the long-named option actually found.
  2099.    Only valid when a long-named option was found. */
  2100.  
  2101. int option_index;
  2102.  
  2103. /* Handle permutation of arguments.  */
  2104.  
  2105. /* Describe the part of ARGV that contains non-options that have
  2106.    been skipped.  `first_nonopt' is the index in ARGV of the first of them;
  2107.    `last_nonopt' is the index after the last of them.  */
  2108.  
  2109. static int first_nonopt;
  2110. static int last_nonopt;
  2111.  
  2112. /* Exchange two adjacent subsequences of ARGV.
  2113.    One subsequence is elements [first_nonopt,last_nonopt)
  2114.     which contains all the non-options that have been skipped so far.
  2115.    The other is elements [last_nonopt,optind), which contains all
  2116.     the options processed since those non-options were skipped.
  2117.  
  2118.    `first_nonopt' and `last_nonopt' are relocated so that they describe
  2119.     the new indices of the non-options in ARGV after they are moved.  */
  2120.  
  2121. static void
  2122. exchange (argv)
  2123.      char **argv;
  2124.  
  2125. {
  2126.   int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
  2127.   char **temp = (char **) alloca (nonopts_size);
  2128.  
  2129.   /* Interchange the two blocks of data in ARGV.  */
  2130.  
  2131.   bcopy (&argv[first_nonopt], temp, nonopts_size);
  2132.   bcopy (&argv[last_nonopt], &argv[first_nonopt],
  2133.    (optind - last_nonopt) * sizeof (char *));
  2134.   bcopy (temp, &argv[first_nonopt + optind - last_nonopt], nonopts_size);
  2135.  
  2136.   /* Update records for the slots the non-options now occupy.  */
  2137.  
  2138.   first_nonopt += (optind - last_nonopt);
  2139.   last_nonopt = optind;
  2140. }
  2141.  
  2142. /* Scan elements of ARGV (whose length is ARGC) for option characters
  2143.    given in OPTSTRING.
  2144.  
  2145.    If an element of ARGV starts with '-', and is not exactly "-" or "--",
  2146.    then it is an option element.  The characters of this element
  2147.    (aside from the initial '-') are option characters.  If `getopt'
  2148.    is called repeatedly, it returns successively each of the option characters
  2149.    from each of the option elements.
  2150.  
  2151.    If `getopt' finds another option character, it returns that character,
  2152.    updating `optind' and `nextchar' so that the next call to `getopt' can
  2153.    resume the scan with the following option character or ARGV-element.
  2154.  
  2155.    If there are no more option characters, `getopt' returns `EOF'.
  2156.    Then `optind' is the index in ARGV of the first ARGV-element
  2157.    that is not an option.  (The ARGV-elements have been permuted
  2158.    so that those that are not options now come last.)
  2159.  
  2160.    OPTSTRING is a string containing the legitimate option characters.
  2161.    If an option character is seen that is not listed in OPTSTRING,
  2162.    return '?' after printing an error message.  If you set `opterr' to
  2163.    zero, the error message is suppressed but we still return '?'.
  2164.  
  2165.    If a char in OPTSTRING is followed by a colon, that means it wants an arg,
  2166.    so the following text in the same ARGV-element, or the text of the following
  2167.    ARGV-element, is returned in `optarg'.  Two colons mean an option that
  2168.    wants an optional arg; if there is text in the current ARGV-element,
  2169.    it is returned in `optarg', otherwise `optarg' is set to zero.
  2170.  
  2171.    If OPTSTRING starts with `-' or `+', it requests different methods of
  2172.    handling the non-option ARGV-elements.
  2173.    See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
  2174.  
  2175.    Long-named options begin with `+' instead of `-'.
  2176.    Their names may be abbreviated as long as the abbreviation is unique
  2177.    or is an exact match for some defined option.  If they have an
  2178.    argument, it follows the option name in the same ARGV-element, separated
  2179.    from the option name by a `=', or else the in next ARGV-element.
  2180.    When `getopt' finds a long-named option, it returns 0 if that option's
  2181.    `flag' field is nonzero, the value of the option's `val' field
  2182.    otherwise.  */
  2183.  
  2184. int
  2185. getopt (argc, argv, optstring)
  2186.      int argc;
  2187. char **argv;
  2188. CONST char *optstring;
  2189.  
  2190. {
  2191.   optarg = 0;
  2192.  
  2193.   /* Initialize the internal data when the first call is made.
  2194.      Start processing options with ARGV-element 1 (since ARGV-element 0
  2195.      is the program name); the sequence of previously skipped
  2196.      non-option ARGV-elements is empty.  */
  2197.  
  2198.   if (optind == 0)
  2199.   {
  2200.     first_nonopt = last_nonopt = optind = 1;
  2201.  
  2202.     nextchar = 0;
  2203.  
  2204.       /* Determine how to handle the ordering of options and nonoptions.  */
  2205.  
  2206.     if (optstring[0] == '-')
  2207.     {
  2208.       ordering = RETURN_IN_ORDER;
  2209.       ++optstring;
  2210.     }
  2211.     else if (optstring[0] == '+')
  2212.     {
  2213.       ordering = REQUIRE_ORDER;
  2214.       ++optstring;
  2215.     }
  2216.     else if (getenv ("_POSIX_OPTION_ORDER") != 0)
  2217.       ordering = REQUIRE_ORDER;
  2218.     else
  2219.       ordering = PERMUTE;
  2220.   }
  2221.  
  2222.   if (nextchar == NULL || *nextchar == 0)
  2223.   {
  2224.     if (ordering == PERMUTE)
  2225.     {
  2226.     /* If we have just processed some options following some non-options,
  2227.        exchange them so that the options come first.  */
  2228.       if (first_nonopt != last_nonopt && last_nonopt != optind)
  2229.         exchange (argv);
  2230.       else if (last_nonopt != optind)
  2231.         first_nonopt = optind;
  2232.  
  2233.     /* Now skip any additional non-options
  2234.        and extend the range of non-options previously skipped.  */
  2235.  
  2236.       while (optind < argc
  2237.        && (argv[optind][0] != '-'
  2238.            || argv[optind][1] == 0)
  2239.        && (_getopt_long_options == 0
  2240.            || argv[optind][0] != '+'
  2241.            || argv[optind][1] == 0))
  2242.         optind++;
  2243.       last_nonopt = optind;
  2244.     }
  2245.  
  2246.       /* Special ARGV-element `--' means premature end of options.
  2247.    Skip it like a null option,
  2248.    then exchange with previous non-options as if it were an option,
  2249.    then skip everything else like a non-option.  */
  2250.  
  2251.     if (optind != argc && !strcmp (argv[optind], "--"))
  2252.     {
  2253.       optind++;
  2254.  
  2255.       if (first_nonopt != last_nonopt && last_nonopt != optind)
  2256.         exchange (argv);
  2257.       else if (first_nonopt == last_nonopt)
  2258.         first_nonopt = optind;
  2259.       last_nonopt = argc;
  2260.  
  2261.       optind = argc;
  2262.     }
  2263.  
  2264.       /* If we have done all the ARGV-elements, stop the scan
  2265.    and back over any non-options that we skipped and permuted.  */
  2266.  
  2267.     if (optind == argc)
  2268.     {
  2269.     /* Set the next-arg-index to point at the non-options
  2270.        that we previously skipped, so the caller will digest them.  */
  2271.       if (first_nonopt != last_nonopt)
  2272.         optind = first_nonopt;
  2273.       return EOF;
  2274.     }
  2275.  
  2276.       /* If we have come to a non-option and did not permute it,
  2277.    either stop the scan or describe it to the caller and pass it by.  */
  2278.  
  2279.     if ((argv[optind][0] != '-' || argv[optind][1] == 0)
  2280.   && (_getopt_long_options == 0
  2281.       || argv[optind][0] != '+' || argv[optind][1] == 0))
  2282.     {
  2283.       if (ordering == REQUIRE_ORDER)
  2284.         return EOF;
  2285.       optarg = argv[optind++];
  2286.       return 1;
  2287.     }
  2288.  
  2289.       /* We have found another option-ARGV-element.
  2290.    Start decoding its characters.  */
  2291.  
  2292.     nextchar = argv[optind] + 1;
  2293.   }
  2294.  
  2295.   if (_getopt_long_options != 0
  2296.       && (argv[optind][0] == '+'
  2297.     || (_getopt_long_only && argv[optind][0] == '-'))
  2298.     )
  2299.   {
  2300.     CONST struct option *p;
  2301.     char *s = nextchar;
  2302.     int exact = 0;
  2303.     int ambig = 0;
  2304.     CONST struct option *pfound = NULL;
  2305.     int indfound;
  2306.  
  2307.     while (*s && *s != '=')
  2308.       s++;
  2309.  
  2310.       /* Test all options for either exact match or abbreviated matches.  */
  2311.     for (p = _getopt_long_options, option_index = 0; p->name;
  2312.    p++, option_index++)
  2313.       if (!strncmp (p->name, nextchar, s - nextchar))
  2314.       {
  2315.         if (s - nextchar == strlen (p->name))
  2316.         {
  2317.     /* Exact match found.  */
  2318.           pfound = p;
  2319.           indfound = option_index;
  2320.           exact = 1;
  2321.           break;
  2322.         }
  2323.         else if (pfound == NULL)
  2324.         {
  2325.     /* First nonexact match found.  */
  2326.           pfound = p;
  2327.           indfound = option_index;
  2328.         }
  2329.         else
  2330.         /* Second nonexact match found.  */
  2331.           ambig = 1;
  2332.       }
  2333.  
  2334.     if (ambig && !exact)
  2335.     {
  2336.       fprintf (stderr, "%s: option `%s' is ambiguous\n",
  2337.          argv[0], argv[optind]);
  2338.       nextchar += strlen (nextchar);
  2339.       optind++;
  2340.       return '?';
  2341.     }
  2342.  
  2343.     if (pfound != NULL)
  2344.     {
  2345.       option_index = indfound;
  2346.       optind++;
  2347.       if (*s)
  2348.       {
  2349.         if (pfound->has_arg > 0)
  2350.           optarg = s + 1;
  2351.         else
  2352.         {
  2353.           fprintf (stderr,
  2354.              "%s: option `%c%s' doesn't allow an argument\n",
  2355.              argv[0], argv[optind - 1][0], pfound->name);
  2356.           nextchar += strlen (nextchar);
  2357.           return '?';
  2358.         }
  2359.       }
  2360.       else if (pfound->has_arg == 1)
  2361.       {
  2362.         if (optind < argc)
  2363.           optarg = argv[optind++];
  2364.         else
  2365.         {
  2366.           fprintf (stderr, "%s: option `%s' requires an argument\n",
  2367.              argv[0], argv[optind - 1]);
  2368.           nextchar += strlen (nextchar);
  2369.           return '?';
  2370.         }
  2371.       }
  2372.       nextchar += strlen (nextchar);
  2373.       if (pfound->flag)
  2374.       {
  2375.         *(pfound->flag) = pfound->val;
  2376.         return 0;
  2377.       }
  2378.       return pfound->val;
  2379.     }
  2380.       /* Can't find it as a long option.  If this is getopt_long_only,
  2381.    and the option starts with '-' and is a valid short
  2382.    option, then interpret it as a short option.  Otherwise it's
  2383.    an error.  */
  2384.     if (_getopt_long_only == 0 || argv[optind][0] == '+' ||
  2385.   index (optstring, *nextchar) == NULL)
  2386.     {
  2387.       if (opterr != 0)
  2388.         fprintf (stderr, "%s: unrecognized option `%c%s'\n",
  2389.            argv[0], argv[optind][0], nextchar);
  2390.       nextchar += strlen (nextchar);
  2391.       optind++;
  2392.       return '?';
  2393.     }
  2394.   }
  2395.  
  2396.   /* Look at and handle the next option-character.  */
  2397.  
  2398.   {
  2399.     char c = *nextchar++;
  2400.     char *temp = index (optstring, c);
  2401.  
  2402.     /* Increment `optind' when we start to process its last character.  */
  2403.     if (*nextchar == 0)
  2404.       optind++;
  2405.  
  2406.     if (temp == 0 || c == ':')
  2407.     {
  2408.       if (opterr != 0)
  2409.       {
  2410.         if (c < 040 || c >= 0177)
  2411.           fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
  2412.              argv[0], c);
  2413.         else
  2414.           fprintf (stderr, "%s: unrecognized option `-%c'\n",
  2415.              argv[0], c);
  2416.       }
  2417.       return '?';
  2418.     }
  2419.     if (temp[1] == ':')
  2420.     {
  2421.       if (temp[2] == ':')
  2422.       {
  2423.       /* This is an option that accepts an argument optionally.  */
  2424.         if (*nextchar != 0)
  2425.         {
  2426.           optarg = nextchar;
  2427.           optind++;
  2428.         }
  2429.         else
  2430.           optarg = NULL;
  2431.         nextchar = NULL;
  2432.       }
  2433.       else
  2434.       {
  2435.       /* This is an option that requires an argument.  */
  2436.         if (*nextchar != 0)
  2437.         {
  2438.           optarg = nextchar;
  2439.     /* If we end this ARGV-element by taking the rest as an arg,
  2440.        we must advance to the next element now.  */
  2441.           optind++;
  2442.         }
  2443.         else if (optind == argc)
  2444.         {
  2445.           if (opterr != 0)
  2446.             fprintf (stderr, "%s: option `-%c' requires an argument\n",
  2447.                argv[0], c);
  2448.           c = '?';
  2449.         }
  2450.         else
  2451.         /* We already incremented `optind' once;
  2452.      increment it again when taking next ARGV-elt as argument.  */
  2453.           optarg = argv[optind++];
  2454.         nextchar = 0;
  2455.       }
  2456.     }
  2457.     return c;
  2458.   }
  2459. }
  2460.  
  2461. /* Getopt for GNU.
  2462.    Copyright (C) 1987, 1989 Free Software Foundation, Inc.
  2463.  
  2464.    This program is free software; you can redistribute it and/or modify
  2465.    it under the terms of the GNU General Public License as published by
  2466.    the Free Software Foundation; either version 1, or (at your option)
  2467.    any later version.
  2468.  
  2469.    This program is distributed in the hope that it will be useful,
  2470.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  2471.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  2472.    GNU General Public License for more details.
  2473.  
  2474.    You should have received a copy of the GNU General Public License
  2475.    along with this program; if not, write to the Free Software
  2476.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  2477.  
  2478.  
  2479. #ifdef __STDC__
  2480. #define CONST const
  2481. #else
  2482. #define CONST
  2483. #endif
  2484.  
  2485. #if !defined (NULL)
  2486. #define NULL ((void *)0)
  2487. #endif
  2488.  
  2489. int
  2490. getopt_long (argc, argv, options, long_options, opt_index)
  2491. int argc;
  2492. char **argv;
  2493. CONST char *options;
  2494. CONST struct option *long_options;
  2495. int *opt_index;
  2496.  
  2497. {
  2498.   int val;
  2499.  
  2500.   _getopt_long_options = long_options;
  2501.  
  2502.   val = getopt (argc, argv, options);
  2503.   if (val == 0 && opt_index != NULL)
  2504.     *opt_index = option_index;
  2505.   return val;
  2506. }
  2507.  
  2508. /* Like getopt_long, but '-' as well as '+' can indicate a long option.
  2509.    If an option that starts with '-' doesn't match a long option,
  2510.    but does match a short option, it is parsed as a short option
  2511.    instead. */
  2512.  
  2513. int
  2514. getopt_long_only (argc, argv, options, long_options, opt_index)
  2515.      int argc;
  2516. char **argv;
  2517. CONST char *options;
  2518. CONST struct option *long_options;
  2519. int *opt_index;
  2520.  
  2521. {
  2522.   int val;
  2523.  
  2524.   _getopt_long_options = long_options;
  2525.   _getopt_long_only = 1;
  2526.   val = getopt (argc, argv, options);
  2527.   if (val == 0 && opt_index != NULL)
  2528.     *opt_index = option_index;
  2529.   return val;
  2530. }
  2531.  
  2532.  
  2533. /* argmatch.c -- find a match for a string in an array
  2534.    Copyright (C) 1990 Free Software Foundation, Inc.
  2535.  
  2536.    This program is free software; you can redistribute it and/or modify
  2537.    it under the terms of the GNU General Public License as published by
  2538.    the Free Software Foundation; either version 1, or (at your option)
  2539.    any later version.
  2540.  
  2541.    This program is distributed in the hope that it will be useful,
  2542.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  2543.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  2544.    GNU General Public License for more details.
  2545.  
  2546.    You should have received a copy of the GNU General Public License
  2547.    along with this program; if not, write to the Free Software
  2548.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  2549.  
  2550. /* Written by David MacKenzie <djm@ai.mit.edu> */
  2551.  
  2552.  
  2553. extern char *program_name;
  2554.  
  2555. /* If ARG is an unambiguous match for an element of the
  2556.    null-terminated array OPTLIST, return the index in OPTLIST
  2557.    of the matched element, else -1 if it does not match any element
  2558.    or -2 if it is ambiguous (is a prefix of more than one element). */
  2559.  
  2560. int
  2561. argmatch (arg, optlist)
  2562.      char *arg;
  2563. char **optlist;
  2564.  
  2565. {
  2566.   int i;      /* Temporary index in OPTLIST. */
  2567.   int arglen;     /* Length of ARG. */
  2568.   int matchind = -1;    /* Index of first nonexact match. */
  2569.   int ambiguous = 0;    /* If nonzero, multiple nonexact match(es). */
  2570.  
  2571.   arglen = strlen (arg);
  2572.   
  2573.   /* Test all elements for either exact match or abbreviated matches.  */
  2574.   for (i = 0; optlist[i]; i++)
  2575.   {
  2576.     if (!strncmp (optlist[i], arg, arglen))
  2577.     {
  2578.       if (strlen (optlist[i]) == arglen)
  2579.       /* Exact match found.  */
  2580.         return i;
  2581.       else if (matchind == -1)
  2582.       /* First nonexact match found.  */
  2583.         matchind = i;
  2584.       else
  2585.       /* Second nonexact match found.  */
  2586.         ambiguous = 1;
  2587.     }
  2588.   }
  2589.   if (ambiguous)
  2590.     return -2;
  2591.   else
  2592.     return matchind;
  2593. }
  2594.  
  2595. /* Error reporting for argmatch.
  2596.    KIND is a description of the type of entity that was being matched.
  2597.    VALUE is the invalid value that was given.
  2598.    PROBLEM is the return value from argmatch. */
  2599.  
  2600. void
  2601. invalid_arg (kind, value, problem)
  2602.      char *kind;
  2603. char *value;
  2604. int problem;
  2605.  
  2606. {
  2607.   fprintf (stderr, "%s: ", program_name);
  2608.   if (problem == -1)
  2609.     fprintf (stderr, "invalid");
  2610.   else        /* Assume -2. */
  2611.     fprintf (stderr, "ambiguous");
  2612.   fprintf (stderr, " %s `%s'\n", kind, value);
  2613. }
  2614. /* File-name wildcard pattern matching for GNU.
  2615.    Copyright (C) 1985, 1988, 1989, 1990 Free Software Foundation, Inc.
  2616.  
  2617.    This program is free software; you can redistribute it and/or modify
  2618.    it under the terms of the GNU General Public License as published by
  2619.    the Free Software Foundation; either version 1, or (at your option)
  2620.    any later version.
  2621.  
  2622.    This program is distributed in the hope that it will be useful,
  2623.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  2624.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  2625.    GNU General Public License for more details.
  2626.  
  2627.    You should have received a copy of the GNU General Public License
  2628.    along with this program; if not, write to the Free Software
  2629.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  2630.  
  2631. /* To whomever it may concern: I have never seen the code which most
  2632.    Unix programs use to perform this function.  I wrote this from scratch
  2633.    based on specifications for the pattern matching.  --RMS.  */
  2634.  
  2635. static int glob_match_after_star ();
  2636.  
  2637. /* Return nonzero if PATTERN has any special globbing chars in it.  */
  2638.  
  2639. int
  2640. glob_pattern_p (pattern)
  2641.      char *pattern;
  2642.  
  2643. {
  2644.   register char *p = pattern;
  2645.   register char c;
  2646.  
  2647.   while ((c = *p++) != '\0')
  2648.     switch (c)
  2649.     {
  2650.       case '?':
  2651.       case '[':
  2652.       case '*':
  2653.         return 1;
  2654.  
  2655.       case '\\':
  2656.         if (*p++ == '\0')
  2657.           return 0;
  2658.     }
  2659.  
  2660.   return 0;
  2661. }
  2662.  
  2663.  
  2664. /* Match the pattern PATTERN against the string TEXT;
  2665.    return 1 if it matches, 0 otherwise.
  2666.  
  2667.    A match means the entire string TEXT is used up in matching.
  2668.  
  2669.    In the pattern string, `*' matches any sequence of characters,
  2670.    `?' matches any character, [SET] matches any character in the specified set,
  2671.    [!SET] matches any character not in the specified set.
  2672.  
  2673.    A set is composed of characters or ranges; a range looks like
  2674.    character hyphen character (as in 0-9 or A-Z).
  2675.    [0-9a-zA-Z_] is the set of characters allowed in C identifiers.
  2676.    Any other character in the pattern must be matched exactly.
  2677.  
  2678.    To suppress the special syntactic significance of any of `[]*?!-\',
  2679.    and match the character exactly, precede it with a `\'.
  2680.  
  2681.    If DOT_SPECIAL is nonzero,
  2682.    `*' and `?' do not match `.' at the beginning of TEXT.  */
  2683.  
  2684. int
  2685. glob_match (pattern, text, dot_special)
  2686.      char *pattern, *text;
  2687. int dot_special;
  2688.  
  2689. {
  2690.   register char *p = pattern, *t = text;
  2691.   register char c;
  2692.  
  2693.   while ((c = *p++) != '\0')
  2694.     switch (c)
  2695.     {
  2696.       case '?':
  2697.         if (*t == '\0' || (dot_special && t == text && *t == '.'))
  2698.           return 0;
  2699.         else
  2700.           ++t;
  2701.         break;
  2702.  
  2703.       case '\\':
  2704.         if (*p++ != *t++)
  2705.           return 0;
  2706.         break;
  2707.  
  2708.       case '*':
  2709.         if (dot_special && t == text && *t == '.')
  2710.           return 0;
  2711.         return glob_match_after_star (p, t);
  2712.  
  2713.       case '[':
  2714.         {
  2715.           register char c1 = *t++;
  2716.           int invert;
  2717.  
  2718.           if (c1 == '\0')
  2719.             return 0;
  2720.  
  2721.           invert = (*p == '!');
  2722.  
  2723.           if (invert)
  2724.             p++;
  2725.  
  2726.           c = *p++;
  2727.           while (1)
  2728.           {
  2729.             register char cstart = c, cend = c;
  2730.  
  2731.             if (c == '\\')
  2732.             {
  2733.               cstart = *p++;
  2734.               cend = cstart;
  2735.             }
  2736.  
  2737.             if (cstart == '\0')
  2738.               return 0; /* Missing ']'. */
  2739.  
  2740.             c = *p++;
  2741.  
  2742.             if (c == '-')
  2743.             {
  2744.               cend = *p++;
  2745.               if (cend == '\\')
  2746.                 cend = *p++;
  2747.               if (cend == '\0')
  2748.                 return 0;
  2749.               c = *p++;
  2750.             }
  2751.             if (c1 >= cstart && c1 <= cend)
  2752.               goto match;
  2753.             if (c == ']')
  2754.               break;
  2755.           }
  2756.           if (!invert)
  2757.             return 0;
  2758.           break;
  2759.  
  2760. match:
  2761.     /* Skip the rest of the [...] construct that already matched.  */
  2762.           while (c != ']')
  2763.           {
  2764.             if (c == '\0')
  2765.               return 0;
  2766.             c = *p++;
  2767.             if (c == '\0')
  2768.               return 0;
  2769.             if (c == '\\')
  2770.               p++;
  2771.           }
  2772.           if (invert)
  2773.             return 0;
  2774.           break;
  2775.         }
  2776.  
  2777.       default:
  2778.         if (c != *t++)
  2779.           return 0;
  2780.     }
  2781.  
  2782.   return *t == '\0';
  2783. }
  2784.  
  2785. /* Like glob_match, but match PATTERN against any final segment of TEXT.  */
  2786.  
  2787. static int
  2788. glob_match_after_star (pattern, text)
  2789.      char *pattern, *text;
  2790.  
  2791. {
  2792.   register char *p = pattern, *t = text;
  2793.   register char c, c1;
  2794.  
  2795.   while ((c = *p++) == '?' || c == '*')
  2796.     if (c == '?' && *t++ == '\0')
  2797.       return 0;
  2798.  
  2799.   if (c == '\0')
  2800.     return 1;
  2801.  
  2802.   if (c == '\\')
  2803.     c1 = *p;
  2804.   else
  2805.     c1 = c;
  2806.  
  2807.   --p;
  2808.   while (1)
  2809.   {
  2810.     if ((c == '[' || *t == c1) && glob_match (p, t, 0))
  2811.       return 1;
  2812.     if (*t++ == '\0')
  2813.       return 0;
  2814.   }
  2815. }
  2816. /* error.c -- error handler for noninteractive utilities
  2817.    Copyright (C) 1990 Free Software Foundation, Inc.
  2818.  
  2819.    This program is free software; you can redistribute it and/or modify
  2820.    it under the terms of the GNU General Public License as published by
  2821.    the Free Software Foundation; either version 1, or (at your option)
  2822.    any later version.
  2823.  
  2824.    This program is distributed in the hope that it will be useful,
  2825.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  2826.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  2827.    GNU General Public License for more details.
  2828.  
  2829.    You should have received a copy of the GNU General Public License
  2830.    along with this program; if not, write to the Free Software
  2831.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  2832.  
  2833. /* David MacKenzie */
  2834.  
  2835.  
  2836. /* MY GOD [NDC] */
  2837. #define va_alist a1, a2, a3, a4, a5, a6, a7, a8
  2838. #define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
  2839.  
  2840. void exit ();
  2841. #if 0
  2842. static char *
  2843. strerror (errnum)
  2844.      int errnum;
  2845.  
  2846. {
  2847.   extern char *sys_errlist[];
  2848.   extern int sys_nerr;
  2849.  
  2850.   if (errnum > 0 && errnum < sys_nerr)
  2851.     return sys_errlist[errnum];
  2852.   return "Unknown system error";
  2853. }
  2854. #endif
  2855. /* Print the program name and error message MESSAGE, which is a printf-style
  2856.    format string with optional args.
  2857.    If ERRNUM is nonzero, print its corresponding system error message.
  2858.    Exit with status STATUS if it is nonzero. */
  2859. /* VARARGS */
  2860. void
  2861. error (status, errnum, message, va_alist)
  2862. int status;
  2863. int errnum;
  2864. char *message;
  2865. va_dcl
  2866.  
  2867. {
  2868.   extern char *program_name;
  2869.  
  2870.   fprintf (stderr, "%s: ", program_name);
  2871.  
  2872.   fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
  2873.  
  2874.   if (errnum)
  2875.     fprintf (stderr, ": %s", strerror (errnum));
  2876.   putc ('\n', stderr);
  2877.   fflush (stderr);
  2878.   if (status)
  2879.     exit (status);
  2880. }
  2881. /* ========================== MAIN PROGRAM ============================== */
  2882. #if defined(SKELETON)
  2883. int cfls(int argc, char **argv)
  2884. #else
  2885. void main (int argc, char **argv)
  2886. #endif
  2887.  
  2888. {
  2889. register int i;
  2890. register struct pending *thispend;
  2891.  
  2892.  
  2893. #if !defined(SKELETON)
  2894.   cfinit("cfls", 400, NULL);
  2895. #endif
  2896.  
  2897.   dir_defaulted = 1;
  2898.   print_dir_name = 1;
  2899.   pending_dirs = NULL;
  2900.   ignore_patterns = NULL;
  2901.   current_time = time ((long *) 0);
  2902.   program_name = argv[0];
  2903.  
  2904.  
  2905.   i = decode_switches (argc, argv);
  2906.  
  2907.   format_needs_stat =
  2908.         sort_type == sort_time
  2909.     ||  sort_type == sort_size
  2910.     ||  format == long_format
  2911.     ||  trace_links 
  2912.     || trace_dirs 
  2913.     || indicator_style != none
  2914. #ifdef PCDOS
  2915.     ||  format == many_per_line
  2916. #endif
  2917.     ||  print_block_size || print_inode;
  2918.  
  2919.   nfiles = 100;
  2920.   files = (struct file *) xmalloc (sizeof (struct file) * nfiles);
  2921.   files_index = 0;
  2922.  
  2923.   clear_files ();
  2924.  
  2925.   if (i < argc)
  2926.     dir_defaulted = 0;
  2927.   for (; i < argc; i++)
  2928.   {
  2929. #ifdef PCDOS
  2930.     lose_backslashes(argv[i]);
  2931. #endif
  2932.     gobble_file (argv[i], 1, "", NULL);
  2933.   }
  2934.   if (dir_defaulted)
  2935.   {
  2936.     if (immediate_dirs)
  2937.       gobble_file (".", 1, "", NULL);
  2938.     else
  2939.       queue_directory (".", NULL, NULL);
  2940.   }
  2941.  
  2942.   if (files_index)
  2943.   {
  2944.     sort_files ();
  2945.     if (!immediate_dirs)
  2946.       extract_dirs_from_files ("", 0, NULL);
  2947.       /* `files_index' might be zero now.  */
  2948.   }
  2949.   if (files_index)
  2950.   {
  2951.     print_current_files ();
  2952.     if (pending_dirs)
  2953.       putchar ('\n');
  2954.   }
  2955.   else if (!trace_dirs && pending_dirs && pending_dirs->next == NULL)
  2956.     print_dir_name = 0;
  2957.  
  2958.   while (pending_dirs)
  2959.   {
  2960.     thispend = pending_dirs;
  2961.     pending_dirs = pending_dirs->next;
  2962.     print_dir (thispend);
  2963.     free (thispend->name);
  2964.     if (thispend->realname)
  2965.       free (thispend->realname);
  2966.     free (thispend);
  2967.     print_dir_name = 1;
  2968.   }
  2969. #if !defined(SKELETON)
  2970.     cfexit();
  2971.     exit(0);
  2972. #else
  2973.   return 0;
  2974. #endif
  2975. }
  2976.  
  2977.